#include "bspline.h"
#include <QDebug>

BSpline::BSpline()
{

}

QVector<QPointF> BSpline::generateCurve(QVector<QPointF> basePoints, int currentK, double step)
{
    QVector<QPointF> curvePoints;
    QVector<QPointF> ctrlPoints = basePoints;
//    QVector<QPointF> ctrlPoints = getCtrlPoint(basePoints);
    curvePoints.clear();
    for(double u=currentK; u<ctrlPoints.size(); u+=step)
    {
//        qDebug()<<u;
        QPointF tmp(0,0);
        for(int i=0; i<ctrlPoints.size();i++)
        {
            QPointF t = ctrlPoints[i];
            t*=N(currentK,i,u);
            tmp+=t;
        }

        curvePoints.push_back(tmp);
    }
    qDebug()<<ctrlPoints.count()<<curvePoints.count();
    return curvePoints;
}

QVector<QPointF> BSpline::getCtrlPoint(QVector<QPointF> basePoints)
{
    QVector<QPointF> ctrlPoints;
    QPointF last,cur,next,nnext;

    for(int i=0; i<basePoints.count(); i++)
    {
        QPointF ctrlA,ctrlB;
        cur = basePoints[i];
        if(i == 0)
        {
            last = basePoints[0];
            next = basePoints[1];
            nnext = basePoints[2];
        }
        else if(i == (basePoints.count()-2))
        {
            last = basePoints[i-1];
            next = basePoints[i+1];
            nnext = basePoints[i+1];
        }
        else
        {
            last = basePoints[i-1];
            next = basePoints[i+1];
            nnext = basePoints[i+2];
        }

        ctrlA.setX(cur.x()+(next.x()-last.x())/4);
        ctrlA.setY(cur.y()+(next.y()-last.y())/4);
        ctrlB.setX(next.x()-(nnext.x()-cur.x())/4);
        ctrlB.setY(next.y()+(nnext.y()-cur.y())/4);
        ctrlPoints.push_back(ctrlA);
        ctrlPoints.push_back(ctrlB);
    }
    qDebug()<<"size:"<<ctrlPoints.count()<<basePoints.count();
    return ctrlPoints;
}

double BSpline::N(int k, int i, double u)
{
    switch(k)
    {
    case 1:
        return N1(i,u);
    case 2:
        return N2(i,u);
    case 3:
        return N3(i,u);
    }
    return 0;
}

double BSpline::N1(int i, double u)
{
    double t = u-i;

    if(0<=t && t<1)
        return t;
    if(1<=t && t<2)
        return 2-t;
    return 0;
}

double BSpline::N2(int i, double u)
{
    double t = u-i;

    if(0<=t && t<1)
        return 0.5*t*t;
    if(1<=t && t<2)
        return 3*t-t*t-1.5;
    if(2<=t && t<3)
        return 0.5*pow(3-t,2);
    return 0;
}

double BSpline::N3(int i, double u)
{
    double t = u-i;
    double a = 1.0/6.0;

    if(0<=t && t<1)
        return a*t*t*t;
    if(1<=t && t<2)
        return a*(-3*pow(t-1,3) + 3*pow(t-1,2) + 3*(t-1) +1);
    if(2<=t && t<3)
        return a*(3*pow(t-2,3) - 6*pow(t-2,2) +4);
    if(3<=t && t<4)
        return a*pow(4-t,3);
    return 0;
}
